HIGH-SPEED DECIMAL TO BINARY FOR PICS

Published in EPE Dec '03 issue.

PETER HEMSLEY

Speed up your PIC's data conversion and compression.

MATHS is all about playing with numbers, so let's play and create a
super-fast decimal to 16-bit binary routine for PIC microcontrollers. It is
based on expressing powers of ten in terms of powers of two.

Here are the first five powers of ten:

1     = 1
10    = 8 + 2
100   = 64 + 32 + 4
1000  = 512 + 256 + 128 + 64 + 32 + 8
10000 = 8192 + 1024 + 512 + 256 + 16

If X represents any decimal digit between 0 and 9 then:

X     = (X * 1)
X0    = (X * 8) + (X * 2)
X00   = (X * 64) + (X * 32) + (X * 4)
X000  = (X * 512) + (X * 256) + (X * 128) + (X * 64) + (X * 32) + (X * 8)
X0000 = (X * 8192) + (X * 1024) + (X * 512) + (X * 256) + (X * 16)

These five expressions are the basis on which we can write a routine to
convert a string of decimal digits into binary. The routine is to be
written in assembler so any expression must be conducive to available
processor instructions, namely NIBBLE SWAP, SHIFT LEFT and ADD.

Conducive numbers to work with are:

2   (SHIFT LEFT to multiply by 2)
16  (NIBBLE SWAP to multiply by 16)
256 (The result goes into the high byte of the binary)

If your mind is somewhat blank at this point let's try a simple example to
get the grey matter working.

The number 300 can be written as:

(3 * 64) + (3 * 32) + (3 * 4)

Re-writing it in terms of conducive numbers we get:

3 * 16 * 2 * 2 + 3 * 16 * 2 + 3 * 2 * 2

Now reduce and re-arrange the expression to:

((3 * 16 + 3) * 2 + 3 * 16) * 2 = 300

Check it with your calculator.

This expression can be calculated easily using NIBBLE SWAP, SHIFT LEFT and
ADD.

Ok that was easy enough, so now for the tricky part.

The 1000's and 10000's expressions contain six and five terms respectively.
If we also use SUBTRACT, the number of terms can be reduced to three and
four:

X     = (X * 1)
X0    = (X * 8) + (X * 2)
X00   = (X * 64) + (X * 32) + (X * 4)
X000  = (X * 1024) - (X * 32) + (X * 8)
X0000 = (X * 8192) + (X * 2048) - (X * 256) + (X * 16)

These five expressions can now be written in terms of conducive numbers
and combined to give:

N = (((D1 + D3 + D4 * 256) * 2 + D2 * 16 + D2 + D3 * 256) * 2 - D3 * 16 +
D2 * 16 + D1 + D4 * 16 * 256) * 2 + D4 * 16 + D0 - D4 * 256

Where D0 = ones, D1 = tens, D2 = hundreds, D3 = thousands, D4 = ten
thousands

To save a lot of typing, and you a big headache, the details of how this
expression was arrived at have been omitted. It is simple enough though a
little lengthy.

There is a problem however, it is the -D4 * 256 at the end of the
expression. If the input is greater than 63231 the running total will
exceed the allotted 16 bits. So, again, re-arrange the expression.

N = (((D1 + D3 + D4 * 256) * 2 + D2 * 16 + D2 + D3 * 256) * 2 - D3 * 16 +
D2 * 16 + D1) * 2 + D4 * 16 + D0 - D4 * 256 + D4 * 16 * 256 * 2

Now there is an addition of a large number at the end of the expression,
therefore overflow will not occur.

The PIC routine in Listing 1 is an almost literal translation of this
expression into assembler, with just a few tweaks to make the code more
efficient. The variables may be allocated (equated) to any registers of
your choice.

Incidentally, the routine will work with numbers up to 99999, the 17th bit
(or bit 16) being returned in the carry.

Finally, if your numerical value is expressed in ASCII characters, each
character may be converted to a BCD (binary-coded-decimal) format by
subtracting 48, which makes it easy to then check if it is a valid decimal
digit.

[xh]RESOURCE

This software routine is available from the [i]EPE PCB Service[r] on 3.5in
disk (Disk 6, [i]PIC Tricks[r] folder), for which a nominal handling charge
applies. It is also available for free download from the [i]EPE[r]
Downloads page, accessible via the home page at
[bo]www.epemag.wimborne.co.uk[r]. It is in the [i]PIC Tricks[r] folder, as
file [bo]Dec2Bin16.txt[r].

LISTING 1

; 5 digit decimal to 16 (17) bit binary. By Peter Hemsley, March 2003.
; Input decimal digits in D0 (LSD) to D4 (MSD)
; Output 16 bit binary in NUMHI and NUMLO
; No temporary variables required
; Code size: 33 instructions
; Execution time: 33 cycles (excluding Call and Return)
; Returns carry set if > 65535 (and NUMHI-LO MOD 65536)

dec2bin16
    movf  D1,W        ; (D1 + D3) * 2
    addwf D3,W
    movwf NUMLO
    rlf   NUMLO,F

    swapf D2,W        ; + D2 * 16 + D2
    addwf D2,W
    addwf NUMLO,F

    rlf   D4,W        ; + (D4 * 2 + D3) * 256
    addwf D3,W
    movwf NUMHI

    rlf   NUMLO,F     ; * 2
    rlf   NUMHI,F

    swapf D3,W        ; - D3 * 16
    subwf NUMLO,F
    skpc
    decf  NUMHI,F

    swapf D2,W        ; + D2 * 16 + D1
    addwf D1,W
    addwf NUMLO,F
    skpnc
    incf  NUMHI,F

    swapf D4,W        ; + D4 * 16 + D0
    addwf D0,W

    rlf   NUMLO,F     ; * 2
    rlf   NUMHI,F

    addwf NUMLO,F
    skpnc
    incf  NUMHI,F

    movf  D4,W        ; - D4 * 256
    subwf NUMHI,F

    swapf D4,W        ; + D4 * 16 * 256 * 2
    addwf NUMHI,F
    addwf NUMHI,F

    return            ; Q.E.D.
